package com.digital.welcome.websocket.mywebsocket;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.function.Supplier;

import javax.websocket.Session;

import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.digital.welcome.util.ApplicationContextUtils;
import com.digital.welcome.websocket.mywebsocket.model.WebSocketMessage;
import com.digital.welcome.websocket.mywebsocket.model.WebSocketMessageEvent;
import com.digital.welcome.websocket.mywebsocket.model.WebSocketMessageType;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.func.Func;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class WebSocketMessageService implements IWebSocketMessageService {

    private HashMap<Long, Session> webSocketServerCollection = new HashMap<Long, Session>();

    public HashMap<Long, Session> getWebSocketServerCollection() {return webSocketServerCollection;}

    private HashMap<Integer, Func<Pair<IWebSocketSession, ArrayList<WebSocketMessage>>, ArrayList<WebSocketMessage>>> eventHandlerCollection = new HashMap<Integer, Func<Pair<IWebSocketSession, ArrayList<WebSocketMessage>>, ArrayList<WebSocketMessage>>>();

    private Boolean isAddedPipelines = false;
    /// <summary>
    /// 向WebSocket消息添加处理事件
    /// </summary>
    /// <param name="messageEvent">待处理事件</param>
    /// <param name="EventHandler">处理方法</param>
    @Override
    public IWebSocketMessageService addEventHandler(WebSocketMessageEvent messageEvent,
            Func<Pair<IWebSocketSession, ArrayList<WebSocketMessage>>, ArrayList<WebSocketMessage>> eventHandler) {
        Func<Pair<IWebSocketSession, ArrayList<WebSocketMessage>>, ArrayList<WebSocketMessage>> e = eventHandlerCollection
                .get(messageEvent.Code);
        if (e != null) {
            log.error("[{}] : Add Event {} Failure : A Event Has Existed Or Have The Same Code With Your Event",
                    DateTime.now(), messageEvent.Code);
            return this;
        }
        eventHandlerCollection.put(messageEvent.Code, eventHandler);
        return this;
    }

    public ArrayList<WebSocketMessage> onMessage(IWebSocketSession session, ArrayList<WebSocketMessage> messages) throws Exception {
        
        if(!isAddedPipelines) {
            addPipelines();
            isAddedPipelines = true;
        }


        WebSocketMessage firstMessage = messages.get(0);
        if(firstMessage == null) return null;
        log.debug("[{}] : Received Message Event Code : {}, Try To Find And Execute The Corresponding Handler", DateTime.now(), firstMessage.getMessageEvent().Code);
        
        Func<Pair<IWebSocketSession, ArrayList<WebSocketMessage>>, ArrayList<WebSocketMessage>> eventHandler = eventHandlerCollection.get(firstMessage.getMessageEvent().Code);
        if(eventHandler == null) {
            log.error("[{}] : The Corresponding Handler Of Event {{ Code = {} }} Is Not Found, It Will Cause Exception", DateTime.now(), firstMessage.getMessageEvent().Code);
            return null;
        }
        return eventHandler.call((Pair.of(session, messages)));
    }

    private void addPipelines() {
        IMyWebSocketPipeline pipeline = ApplicationContextUtils.getBean(IMyWebSocketPipeline.class);
        pipeline.myWebSocketExecutor(this);
    }

}
